# -*- coding: utf-8 -*-
"""Sample controller module"""

# turbogears imports
from tg import expose
from tg import redirect, validate, flash, require
from repoze.what import predicates

# third party imports
#from pylons.i18n import ugettext as _
#from repoze.what import predicates

# project specific imports
from crv.lib.base import BaseController
from tg.controllers import RestController
from crv.model import DBSession, metadata
from crv.model.crvmodel import *
from tgext.crud import CrudRestController

from sprox.tablebase import TableBase
from sprox.fillerbase import TableFiller, EditFormFiller
from sprox.formbase import EditableForm, AddRecordForm

#from sprox.dojo.tablebase import DojoTableBase 
#from sprox.dojo.fillerbase import DojoTableFiller
#from sprox.dojo.formbase import AddRecordForm

from tg import request
import cgi

import logging
log = logging.getLogger(__name__)

import tg

tmpstr = tg.config.get('cloudcrv.usessl', 'False')

CloudCRV_UseSSL = False

if tmpstr=="True":
    CloudCRV_UseSSL = True
    
class VMController(CrudRestController):
    model = VM

    class new_form_type(AddRecordForm):
        __model__ = VM
        __omit_fields__ = ['VM_ID']

    class edit_form_type(EditableForm):
        __model__ = VM
        __omit_fields__ = ['VM_ID']
        
    class edit_filler_type(EditFormFiller):
        __model__ = VM
        
    class table_type(TableBase):
        __model__ = VM
        __xml_fields__ = ['role']
        
    class table_filler_type(TableFiller):
        __model__ = VM
        def role(self, obj):
            roles = ', '.join(['<a href="/roles/'+str(d.Role_ID)+'/edit">'+d.getAttr("name")+'</a>'
                               for d in obj.role])
            return roles.join(('<div>', '</div>'))

        def attr(self,obj):
            attrs= ", ".join([iattr.name+'='+iattr.value for iattr in obj.attr])
            return attrs
        
        def currentSC(self,obj):
            return obj.SCname[obj.currentSC]

        def targetSC(self,obj):
            return obj.SCname[obj.targetSC]
        
class ClusterController(CrudRestController):
    model = Cluster

    class new_form_type(AddRecordForm):
        __model__ = Cluster
        __omit_fields__ = ['Cluster_ID']

    class edit_form_type(EditableForm):
        __model__ = Cluster
        __omit_fields__ = ['Cluster_ID']
        
    class edit_filler_type(EditFormFiller):
        __model__ = Cluster
        
    class table_type(TableBase):
        __model__ = Cluster
        __xml_fields__ = ['role']
        
    class table_filler_type(TableFiller):
        __model__ = Cluster
        def role(self, obj):
            roles = ', '.join(['<a href="/roles/'+str(d.Role_ID)+'/edit">'+d.getAttr("name")+'</a>'
                               for d in obj.role])
            return roles.join(('<div>', '</div>'))
        
        def attr(self,obj):
            attrs= ", ".join([iattr.name+'='+iattr.value for iattr in obj.attr])
            return attrs

        def currentSC(self,obj):
            return obj.SCname[obj.currentSC]

        def targetSC(self,obj):
            return obj.SCname[obj.targetSC]
        
class RoleController(CrudRestController):
    model = Role

    class new_form_type(AddRecordForm):
        __model__ = Role
        __omit_fields__ = ['Role_ID']

    class edit_form_type(EditableForm):
        __model__ = Role
        __omit_fields__ = ['Role_ID']
        
    class edit_filler_type(EditFormFiller):
        __model__ = Role
        
    class table_type(TableBase):
        __model__ = Role
        __xml_fields__ = ['vm','cluster','roleDef','dependOn']
        
    class table_filler_type(TableFiller):
        __model__ = Role
        def vm(self, obj):
            vms = '<a href="/vms/'+str(obj.vm.VM_ID)+'/edit">'+obj.vm.getAttr("name")+'</a>'
            return vms.join(('<div>', '</div>'))
        
        def roleDef(self, obj):
            roledefs = '<a href="/roledefs/'+str(obj.roleDef.RoleDef_ID)+'/edit">'+obj.roleDef.getAttr("name")+'</a>'
            return roledefs.join(('<div>', '</div>'))
        
        def cluster(self, obj):
            clusters = ', '.join(['<a href="/clusters/'+str(d.Cluster_ID)+'/edit">'+d.getAttr("name")+'</a>'
                               for d in obj.cluster])
            return clusters.join(('<div>', '</div>'))
        
        def dependOn(self, obj):
            dependons = ', '.join(['<a href="/roles/'+str(d.Role_ID)+'/edit">'+d.getAttr("name")+'</a>'
                               for d in obj.dependOn])
            return dependons.join(('<div>', '</div>'))
        
        def currentSC(self,obj):
            return obj.SCname[obj.currentSC]

        def targetSC(self,obj):
            return obj.SCname[obj.targetSC]

        def attr(self,obj):
            attrs= ", ".join([iattr.name+'='+iattr.value for iattr in obj.attr])
            return attrs

        
class RoleDefController(CrudRestController):
    model = RoleDef

    class new_form_type(AddRecordForm):
        __model__ = RoleDef
        __omit_fields__ = ['RoleDef_ID']

    class edit_form_type(EditableForm):
        __model__ = RoleDef
        __omit_fields__ = ['RoleDef_ID']
        
    class edit_filler_type(EditFormFiller):
        __model__ = RoleDef
        
    class table_type(TableBase):
        __model__ = RoleDef
        __xml_fields__=['dependOn','dependOnLocal','dependBy','dependByLocal']
        __omit_fields__ = ['dummyVal']
        
    class table_filler_type(TableFiller):
        __model__ = RoleDef
        def dependOn(self, obj):
            dependons = ', '.join(['<a href="/roledefs/'+str(d.RoleDef_ID)+'/edit">'+d.getAttr("name")+'</a>' for d in obj.dependOn])
            return dependons.join(('<div>', '</div>'))

        def dependOnLocal(self, obj):
            roles = ', '.join(['<a href="/roledefs/'+str(d.RoleDef_ID)+'/edit">'+d.getAttr("name")+'</a>' for d in obj.dependOnLocal])
            return roles.join(('<div>', '</div>'))

        def dependBy(self, obj):
            dependons = ', '.join(['<a href="/roledefs/'+str(d.RoleDef_ID)+'/edit">'+d.getAttr("name")+'</a>' for d in obj.dependBy])
            return dependons.join(('<div>', '</div>'))

        def dependByLocal(self, obj):
            roles = ', '.join(['<a href="/roledefs/'+str(d.RoleDef_ID)+'/edit">'+d.getAttr("name")+'</a>' for d in obj.dependByLocal])
            return roles.join(('<div>', '</div>'))

        def attr(self,obj):
            attrs= ", ".join([iattr.name+'='+iattr.value for iattr in obj.attr])
            return attrs
        
        def currentSC(self,obj):
            return obj.SCname[obj.currentSC]

        def targetSC(self,obj):
            return obj.SCname[obj.targetSC]
        
        

class ClusterAttrController(CrudRestController):
    model = ClusterAttr

    class new_form_type(AddRecordForm):
        __model__ = ClusterAttr
        __omit_fields__ = ['ClusterAttr_ID']

    class edit_form_type(EditableForm):
        __model__ = ClusterAttr
        __omit_fields__ = ['ClusterAttr_ID']
        
    class edit_filler_type(EditFormFiller):
        __model__ = ClusterAttr
        
    class table_type(TableBase):
        __model__ = ClusterAttr
        
    class table_filler_type(TableFiller):
        __model__ = ClusterAttr
        

class RoleAttrController(CrudRestController):
    model = RoleAttr

    class new_form_type(AddRecordForm):
        __model__ = RoleAttr
        __omit_fields__ = ['RoleAttr_ID']

    class edit_form_type(EditableForm):
        __model__ = RoleAttr
        __omit_fields__ = ['RoleAttr_ID']
        
    class edit_filler_type(EditFormFiller):
        __model__ = RoleAttr
        
    class table_type(TableBase):
        __model__ = RoleAttr
        
    class table_filler_type(TableFiller):
        __model__ = RoleAttr
        

class VMAttrController(CrudRestController):
    model = VMAttr

    class new_form_type(AddRecordForm):
        __model__ = VMAttr
        __omit_fields__ = ['VMAttr_ID']

    class edit_form_type(EditableForm):
        __model__ = VMAttr
        __omit_fields__ = ['VMAttr_ID']
        
    class edit_filler_type(EditFormFiller):
        __model__ = VMAttr
        
    class table_type(TableBase):
        __model__ = VMAttr
        
    class table_filler_type(TableFiller):
        __model__ = VMAttr
        
class StatusController(BaseController):

    @expose()
    def setVMAttr(self,vmid,name,value):
        if not self.checkCert(vmid=vmid):
            return "AuthFailed"

        vms = DBSession.query(VM).filter(VM.VM_ID==vmid).all()
        log.info("StatusController::setVMAttr::vmid=%s name=%s, attr=%s"%(vmid,name,value))
        if len(vms)<1:
            transaction.commit()
            return "False"
        vms[0].setAttr(name,value)
        transaction.commit()
        return "True"
        
    @expose()
    def getVMAttr(self,vmid,name):

        if not self.checkCert(vmid=vmid):
            return "AuthFailed"

        vms = DBSession.query(VM).filter(VM.VM_ID==vmid).all()
        log.info("StatusController::getVMAttr::vmid=%s name=%s"%(vmid,name))
        if len(vms)<1:
            transaction.commit()
            return "None"
        ret= vms[0].getAttr(name)
        return str(ret)

    @expose()
    def setRoleAttr(self,roleid,name,value):
        if not self.checkCert(roleid=roleid):
            return "AuthFailed"

        roles = DBSession.query(Role).filter(Role.Role_ID==roleid).all()
        log.info("StatusController::setRoleAttr::roleid=%s name=%s, attr=%s"%(roleid,name,value))
        if len(roles)<1:
            transaction.commit()
            return "False"
        roles[0].setAttr(name,value)
        transaction.commit()
        return "True"
        
    @expose()
    def getRoleAttr(self,roleid,name):

        if not self.checkCert(roleid=roleid):
            return "AuthFailed"

        roles = DBSession.query(Role).filter(Role.Role_ID==roleid).all()
        log.info("StatusController::getRoleAttr::roleid=%s name=%s"%(roleid,name))
        if len(roles)<1:
            transaction.commit()
            return "None"
        ret=roles[0].getAttr(name)
        return str(ret)
            
    @expose()
    def getDependentAttr(self,roleid,name):

        if not self.checkCert(roleid=roleid):
            return "AuthFailed"

        roles = DBSession.query(Role).filter(Role.Role_ID==roleid).all()
        log.info("StatusController::getDependentAttr::roleid=%s name=%s"%(roleid,name))
        if len(roles)<1:
            transaction.commit()
            return "None"
        result=[]
        for irole in roles[0].dependBy:
            attr=irole.getAttr(name)
            if attr!=None:
                result.append(attr)
                
        if len(result)==0:
            return "None"
        return " ".join([a for a in result])
        
    @expose()
    def getProviderAttr(self,roleid,name):

        if not self.checkCert(roleid=roleid):
            return "AuthFailed"

        roles = DBSession.query(Role).filter(Role.Role_ID==roleid).all()
        log.info("StatusController::getProviderAttr::roleid=%s name=%s"%(roleid,name))
        if len(roles)<1:
            transaction.commit()
            return "None"

        result=[]
        for irole in roles[0].dependOn:
            attr=irole.getAttr(name)
            if attr!=None:
                result.append(attr)

        if len(result)==0:
            return "None"
        return " ".join(str(a) for a in result)
    
    @expose()
    def setClusterAttr(self,clusterid,name,value):
        if not self.checkCert(clusterid=clusterid):
            return "AuthFailed"

        clusters = DBSession.query(Cluster).filter(Cluster.Cluster_ID==clusterid).all()
        log.info("StatusController::setClusterAttr::clusterid=%s name=%s, attr=%s"%(clusterid,name,value))
        if len(clusters)<1:
            transaction.commit()
            return "False"
        clusters[0].setAttr(name,value)
        transaction.commit()
        return "True"
        
    @expose()
    def setVMActiveRoleSuccess(self,vmid):
        if not self.checkCert(vmid=vmid):
            return "AuthFailed"

        vms = DBSession.query(VM).filter(VM.VM_ID==vmid).all()
        log.info("StatusController::setVMActiveRoleSuccess::vmid=%s"%(vmid))
        if len(vms)<1:
            return "False"
        
        vm=vms[0]

        for irole in vm.role:
            #In case of applying
            if irole.getAttr("ProfileProvided")=="True":
                irole.setAttr("ProfileApplied","True")
        
            #In case of removing
            if irole.getAttr("ReverseProfileProvided")=="True":
                irole.setAttr("ReverseProfileApplied","True")

        transaction.commit()
        return "True"

    @expose()
    def getRunUpdate(self,vmid,name):
        if not self.checkCert(vmid=vmid):
            return "AuthFailed"
        
        vms = DBSession.query(VM).filter(VM.VM_ID==vmid).all()
        log.info("StatusController::getClusterAttrByVM::vmid=%s name=%s"%(vmid,name))
        if len(vms)<1:
            return "None"
        ret=vms[0].role[0].cluster.getAttr(name)
        return ret
        

    def checkCert(self, vmid=None, roleid=None, clusterid=None):
        
        if not CloudCRV_UseSSL:
            return True

        idset=3
        if vmid is None:
            idset=idset-1
        if roleid is None:
            idset=idset-1
        if clusterid is None:
            idset=idset-1

        if idset!=1:
            raise Exception("checkCert::must set one and only one of vmid, roleid and clusterid")
        
        cert_info = request.environ.get('SSL_CLIENT_S_DN_CN')

        #return False if cert_info not found (meaning the client didn't give a cert)
        if cert_info is None:
            return False

        if int(cert_info) is not int(vmid):
            return "None"
        log.error("Certificate common name does not match id in url, SSL_CLIENT_S_DN_CN=%s, vmid=%s"%(str(cert_info),str(vmid)))
            
        
    @require(predicates.not_anonymous("Only for logged in users"))
    @expose()
    def setClusterTargetSC(self, clusterid, targetsc):
        clusters = DBSession.query(Cluster).filter(Cluster.Cluster_ID==clusterid).all()
        log.info("StatusController::setClusterTargetSC::clusterid=%s, targetsc=%s"%(clusterid,str(targetsc)))
        if len(clusters)<1:
            transaction.commit()
            return "False"

        tsc=int(targetsc)

        #can set to SC_RUNNING only if STOPPED
        if tsc==clusters[0].SC.SC_RUNNING:
            if clusters[0].currentSC==clusters[0].targetSC and clusters[0].targetSC==clusters[0].SC.SC_INITIALIZED:
                clusters[0].targetSC=tsc
                transaction.commit()
                return "True"
            else:
                return "False"

        #can set to SC_STOPPED only if RUNNING
        if tsc==clusters[0].SC.SC_STOPPED:
            if clusters[0].currentSC==clusters[0].targetSC and clusters[0].targetSC==clusters[0].SC.SC_RUNNING:
                clusters[0].targetSC=tsc
                transaction.commit()
                return "True"
            else:
                return "False"

        
